/*  Copyright (C) 2008  Alexander Blyzniuchenko (BlezAlex)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using DC;

namespace MediaDC.Forms
{
    public partial class HubInfoForm : Form
    {
        public readonly HubClient _hubClient;
        private delegate void StringEvent(string data);
        private readonly Font _nickNameFont = new Font("Microsoft Sans Serif", (float)8.25, FontStyle.Bold);
        private readonly Dictionary<string, MyInfoEventArgs> _myInfoTable = new Dictionary<string, MyInfoEventArgs>(1000);
        private Hashtable _items = new Hashtable();

        public HubInfoForm(HubRegistration registration, HubClient hubClient)
        {
            InitializeComponent();
            usersList.SetExStyles();

            _hubClient = hubClient;

            _hubClient.OnConnected += delegate(object sender, StringEventArgs args) { AddLineToChatBox("Connected to " + args.Details); };
            _hubClient.OnError += delegate(object sender, StringEventArgs args) { AddLineToChatBox("Error: " + args.Details); };
            _hubClient.OnChatMessage += delegate(object sender, StringEventArgs args) { AddLineToChatBox(args.Details); };
            _hubClient.OnUserConncected += HubClient_OnUserConncected;
            _hubClient.OnUserLeave += HubClient_OnUserLeave;
            _hubClient.OnNickList += Hc_OnNickList;
            _hubClient.OnMyInfo += HubClient_OnMyInfo;
            _hubClient.OnOPList += HubClient_OnOPList;
            _hubClient.OnUserIPList += HubClient_OnUserIPList;

            AddLineToChatBox("Connecting to " + registration.HubUrl);
            _hubClient.Connect(registration.HubUrl);
            Text = registration.HubUrl;

            usersList.DoubleClick += delegate { if (usersList.SelectedItems.Count > 0) _hubClient.RequestFileList(usersList.SelectedItems[0].Text); };
        }

        private void HubClient_OnUserIPList(object sender, UserIpListEventArgs e)
        {
            if (InvokeRequired)
            {
                Invoke(new EventHandler<UserIpListEventArgs>(HubClient_OnUserIPList), sender, e);
            }
            else
            {
                usersList.BeginUpdate();
                foreach (UserIpEntry entry in e.UserIPList)
                {
                    NickListItem item = (NickListItem) _items[entry.Nick];
                    if (item != null)
                    {
                        item.Ip = entry.IP;
                    }
                }
                usersList.EndUpdate();
            }
        }

        void HubClient_OnOPList(string[] nicks)
        {
            if (InvokeRequired)
            {
                Invoke(new HubClient.StringArrayEvent(HubClient_OnOPList), new object[] { nicks });
            }
            else
            {
                usersList.BeginUpdate();
                foreach (string nick in nicks)
                {
                    string nickT = nick.Trim();
                    ListViewItem[] li = usersList.Items.Find(nickT, false);
                    if (li.Length > 0)
                    {
                        NickListItem item = (NickListItem) li[0];
                        item.IsOp = true;
                    }
                }
                
                usersList.ListViewItemSorter = new ListViewItemComparer(0);
                
                usersList.EndUpdate();
            }
        }

        void HubClient_OnMyInfo(object sender, MyInfoEventArgs e)
        {
            lock (_myInfoTable)
            {
                if (_myInfoTable.ContainsKey(e.Nick))
                    _myInfoTable[e.Nick] = e;
                else
                    _myInfoTable.Add(e.Nick, e);
            }
        }

        void HubClient_OnUserLeave(object sender, StringEventArgs e)
        {
            if (InvokeRequired)
                Invoke(new EventHandler<StringEventArgs>(HubClient_OnUserLeave), sender, e);
            else
            {
                _items.Remove(e.Details);
                usersList.Items.RemoveByKey(e.Details);
            }
        }

        void HubClient_OnUserConncected(object sender, StringEventArgs e)
        {
            if (InvokeRequired)
                Invoke(new EventHandler<StringEventArgs>(HubClient_OnUserConncected), sender, e);
            else
            {
                NickListItem item = new NickListItem(e.Details);
                _items[e.Details] = item;
                usersList.Items.Add(item);
            }
        }


        private void AddLineToChatBox(string lineText)
        {
            if (mainChatBox.InvokeRequired)
            {
                mainChatBox.Invoke(new StringEvent(AddLineToChatBox), lineText);
            }
            else
            {
                mainChatBox.AppendText(Environment.NewLine + lineText);
                if (lineText.StartsWith("<") && lineText.IndexOf(">") > -1)
                {
                    mainChatBox.Select(mainChatBox.TextLength - lineText.Length + 1, lineText.IndexOf(">") - 1);
                    mainChatBox.SelectionFont = _nickNameFont;
                    mainChatBox.DeselectAll();
                }
                mainChatBox.SelectionStart = mainChatBox.TextLength;
                mainChatBox.ScrollToCaret();
            }
        }

        private void Hc_OnNickList(string[] nicks)
        {
            if (InvokeRequired)
            {
                Invoke(new HubClient.StringArrayEvent(Hc_OnNickList), new object[] { nicks });
            }
            else
            {
                usersList.BeginUpdate();
                foreach (string nick in nicks)
                    if (nick.Trim().Length > 0)
                    {
                        NickListItem item = new NickListItem(nick);
                        _items[nick] = item;
                        usersList.Items.Add(item);
                    }
                usersList.EndUpdate();
            }
        }

        private void chatMessageBox_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == '\r')
            {
                _hubClient.SendToChat(chatMessageBox.Text);
                chatMessageBox.Clear();
            }
        }

        private void HubInfoForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing)
                e.Cancel = true;
        }

        private void usersList_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            usersList.ListViewItemSorter = new ListViewItemComparer(e.Column);
        }

        private void updateTimer_Tick(object sender, EventArgs e)
        {
            lock (_myInfoTable)
            {
                usersList.BeginUpdate();
                foreach (string key in _myInfoTable.Keys)
                {
                    MyInfoEventArgs args = _myInfoTable[key];
                    NickListItem item = (NickListItem)_items[args.Nick];
                    if (item != null)
                    {
                        item.Update(_myInfoTable[key]);
                    }
                }
                usersList.EndUpdate();
                _myInfoTable.Clear();
            }
        }
    }

    class ListViewItemComparer : IComparer
    {
        private int col;
        public ListViewItemComparer()
        {
            col = 0;
        }
        public ListViewItemComparer(int column)
        {
            col = column;
        }
        public int Compare(object x, object y)
        {
            NickListItem a = (NickListItem) x;
            NickListItem b = (NickListItem) y;
            switch (col)
            {
                // by op, then nick
                case 0:
                    if (a.IsOp == b.IsOp)
                        return String.Compare(a.Nick, b.Nick);
                    else
                        return b.IsOp.CompareTo(a.IsOp);
       
                // by share
                case 1:
                    return a.ShareSize.CompareTo(b.ShareSize);

                default:
                    return String.Compare(a.SubItems[col].Text, b.SubItems[col].Text);
            }
        }
    }

}
